package org.helgoboss.janana_bootstrapper;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Bundle;
import org.helgoboss.janana.Janana;
import java.util.Set;
import java.util.HashSet;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.io.FileOutputStream;
import java.io.IOException;

public class Activator implements BundleActivator {
    private static BundleContext bundleContext;
    private ServiceReference jananaRef;
    private ServiceReference configurationAdminRef;
    private Janana janana;
    private Set<String> symbolicNamesOfInstalledBundles;
	
	public void start(BundleContext context) throws Exception {
        /* Prepare */
        bundleContext = context;
        injectJanana();        
        
        /* Make sure configuration files exist */
        makeSurePaxLoggingConfigurationFileExists();
        makeSureSystemPropertiesFileExists();
        
        
        /* basic stuff*/        
        makeSureSystemBundleIsInstalled("org.apache.felix.configadmin");
        makeSureSystemBundleIsInstalled("org.apache.felix.prefs");
        makeSureSystemBundleIsInstalled("org.apache.felix.fileinstall");
        
        /* log service for command line feedback */
        makeSureSystemBundleIsInstalled("org.ops4j.pax.logging.pax-logging-api");
        makeSureSystemBundleIsInstalled("org.ops4j.pax.logging.pax-logging-service");
        
        /* Scala bundles */
        makeSureSystemBundleIsInstalled("org.helgoboss.scala-library-osgi");
        makeSureSystemBundleIsInstalled("org.helgoboss.scala-swing-osgi");
        makeSureSystemBundleIsInstalled("org.helgoboss.miglayout-core-osgi");
        makeSureSystemBundleIsInstalled("org.helgoboss.miglayout-swing-osgi");
        makeSureSystemBundleIsInstalled("org.helgoboss.scala-swing-additions");
        makeSureSystemBundleIsInstalled("org.helgoboss.scala-additions");
        makeSureSystemBundleIsInstalled("org.helgoboss.module-support");
        makeSureSystemBundleIsInstalled("org.helgoboss.osgi-additions");
        
        /* basic bundles using scala */
        makeSureSystemBundleIsInstalled("org.helgoboss.system-property-setter");
        
        /* database bundles */
        makeSureSystemBundleIsInstalled("org.helgoboss.javax-persistence-osgi");
        makeSureSystemBundleIsInstalled("com.orientechnologies.orient-commons");
        makeSureSystemBundleIsInstalled("com.orientechnologies.orientdb-core");
        makeSureSystemBundleIsInstalled("org.helgoboss.document-database-api");
        makeSureSystemBundleIsInstalled("org.helgoboss.document-database-orient-impl");
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-database");
        
        /* artwork bundle for providing icons, images etc. */
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-artwork");
        
        /* tray icon bundles so we get quick graphical feedback */
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-api");
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-ref-impl");
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-log-opener");
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-exit");
        
        /* OSGi Bundle Repository bundles */
        makeSureSystemBundleIsInstalled("org.osgi.service.obr");
        makeSureSystemBundleIsInstalled("org.helgoboss.caching-obr-api");
        makeSureSystemBundleIsInstalled("org.helgoboss.caching-obr-ref-impl");
        makeSureSystemBundleIsInstalled("org.helgoboss.obr-facade-api");
        makeSureSystemBundleIsInstalled("org.helgoboss.obr-facade-ref-impl");
        makeSureSystemBundleIsInstalled("org.helgoboss.automatic-obr-installer");
        
        
        /* management bundles */
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-repository-management");
        makeSureSystemBundleIsInstalled("org.helgoboss.janana-tray-resource-management");
	}
        
    private void injectJanana() {
        jananaRef = bundleContext.getServiceReference(Janana.class.getName());
        janana = (Janana) bundleContext.getService(jananaRef);
    }
    
    private void releaseJanana() {
        if (jananaRef != null) {
            janana = null;
            bundleContext.ungetService(jananaRef);
            jananaRef = null;
        }
    }
    
    private void injectSymbolicNamesOfInstalledBundles() {
        symbolicNamesOfInstalledBundles = new HashSet<String>();
        
        for (Bundle bundle: bundleContext.getBundles()) {
            symbolicNamesOfInstalledBundles.add(bundle.getSymbolicName());
        }
    }
    
    private void makeSureSystemBundleIsInstalled(String symbolicName) {
        if (!bundleIsInstalled(symbolicName)) {
            janana.installSystemBundle(symbolicName);
        }
    }
    
    private Set<String> getSymbolicNamesOfInstalledBundles() {
        if (symbolicNamesOfInstalledBundles == null) {
            injectSymbolicNamesOfInstalledBundles();
        }
        return symbolicNamesOfInstalledBundles;
    }
    
    private boolean bundleIsInstalled(String symbolicName) {
        return getSymbolicNamesOfInstalledBundles().contains(symbolicName);
    }
            
    private void makeSurePaxLoggingConfigurationFileExists() {
        File destDir = new File(janana.getUserDataDir(), "etc");
        copyBundleResourceToFileIfNotExists("org.ops4j.pax.logging.cfg", destDir);
    }
    
    private void makeSureSystemPropertiesFileExists() {
        File destDir = new File(janana.getUserDataDir(), "etc");
        copyBundleResourceToFileIfNotExists("org.helgoboss.system_property_setter.cfg", destDir);
    }
    
    private void copyBundleResourceToFileIfNotExists(String resourceName, File destinationDir) {
        File destinationFile = new File(destinationDir, resourceName);
        if (!destinationFile.exists()) {
            destinationDir.mkdirs();
            URL sourceUrl = bundleContext.getBundle().getResource("/" + resourceName);
            try {
                InputStream sourceInputStream = sourceUrl.openStream();
                writeInputStreamToFile(sourceInputStream, destinationFile);
            } catch(IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
    
    
    private void writeInputStreamToFile(InputStream is, File file) {
        FileOutputStream os = null;
        try {
            os = new FileOutputStream(file);
            byte[] buffer = new byte[0xFFFF];
            boolean eof = false;
            while (!eof) {
                int length = is.read(buffer);
                if (length == -1) {
                    eof = true;
                } else {
                    os.write(buffer, 0, length);
                }
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } finally {
            try {
                if (os != null) os.close();
                is.close();
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
    }
    
    

	public void stop(BundleContext context) {
        releaseJanana();
        bundleContext = null;
    }
    
    
}
